let Vue;
// Vuex的store
class Store {
    constructor(options = {}) {
        console.log('MyVuex');
        // 拿到传来的state--直接赋值的话，是不具有响应式的。所以可以把他放进Vue实例的data里面
        // this.state = options.state;
        // 注意下面这种写法，不能是this.state = new Vue({}); ,因为下面定义的属性属性访问器，只有get，没有set，会报错。
        this.s = new Vue({
            data() {
                return {
                    state: options.state
                }
            }
        })
        // 通过上面的方式定义后具有响应式，但是不方便访问，所以写一个属性访问器

        // 设置getters--因为访问getters的时候是用属性的方式，所以这里要把他们定义为属性
        this.getters = {};
        let getters = options.getters;
        Object.keys(getters).forEach(key => {
            // 把每一个key定义在新的getters上
            Object.defineProperty(this.getters, key, {
                get: () => {
                    // 在这里调用定义的函数，并且把state传递进去
                    return getters[key](this.state);
                }
            })
        });
        // 保存mutation中的数据
        this.mutations = options.mutations;
        this.actions = options.actions;
    }
    // 定义一个属性访问器，访问state
    get state() {
        return this.s.state
    }
    // commit 方法，用来触发state元素的变更
    // commit(mutationName, payload) {
    //     this.mutations[mutationName](this.state,payload);
    // }
    // 这里使用的是ES7的赋值方法，而不是上面的那种方法的形式，这样的commit在调用的时候，不至于导致this丢失，
    // 因为箭头函数的this是取决于词法作用域的
    commit = (mutationName, payload)=>{
        this.mutations[mutationName](this.state,payload);
    }
    
    // diapatch方法 触发actions方法
    // dispatch(actionName,payload){
    //     this.actions[actionName](this,payload);
    // }
    dispatch = (actionName,payload) => {
        this.actions[actionName](this,payload);
    }
}

const install = (_Vue) => {
    console.log('Use 的时候，install 自动执行');
    // 判断一下创建的时候是不是有VueX选项，有的话，给挂载在$store上面
    Vue = _Vue;
    // 使用mixin来为每一个创建的组件挂上Vuex
    Vue.mixin({
        // 在这里可以写组件的生命周期，那么每一个创建的组件，都会执行这里的代码
        beforeCreate() {
            // $options 是创建Vue时候传的参数
            if (this.$options && this.$options.store) {
                this.$store = this.$options.store;
            } else {
                // 取父亲身上的Vuex挂在自己的身上
                this.$store = this.$parent && this.$parent.$store
            }
        }
    })
}

export default {
    Store,
    install
}